package com.heaven.service.impl;

import com.heaven.core.entity.UserEntity;

import com.heaven.customerServer.customerController.vo.register.RegisterReq;
import com.heaven.customerServer.customerController.vo.register.RegisterRes;
import com.heaven.service.RegisterService;
import com.heaven.service.UserService;
import com.heaven.utils.MailUtils;
import com.heaven.utils.RedisUtils;
import com.heaven.utils.StringUtils;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class RegisterServiceImpl implements RegisterService {
    // 验证码存储前缀，后接email, 存储的值：{验证码}
    private static final String CHECK_CODE_PREFIX = "CHECK_CODE::";

    @Value("${minio.bucket1}")
    private String bucket;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private MailUtils mailUtils;
    @Resource
    private UserService userService;

    @Override
    public RegisterRes getCheckCodeByEmail(String email) {
        // 验证邮箱是否被注册过
        UserEntity userEntity = userService.selectOne(
                new Query().addCriteria(Criteria.where("email").is(email))
        );
        if(userEntity != null) {
            return new RegisterRes(false, "该邮箱已被注册!");
        }

        // 验证该用户的验证码是否失效，没有失效则无需重新发送验证码
        if(redisUtils.getCacheObject(CHECK_CODE_PREFIX+email) != null) {
            return new RegisterRes(false, "验证码已发送，请检查邮箱");
        }

        //生成6位随记编码+系统时间，系统时间用来防止前端为过有效时间去发送请求
        String checkcode = UUID.randomUUID().toString().substring(0,6); //验证码

        // 发送邮件
        boolean flag = mailUtils.sendHtmlEmail("Heaven注册验证码", StringUtils.format("<p>您的验证码为：<b>{}</b>，3分钟内有效，请不要透露给其他人！</p>", checkcode), email);
        if(flag) {
            // 将验证码存入redis中
            redisUtils.setCacheObject(CHECK_CODE_PREFIX+email,checkcode, 3, TimeUnit.MINUTES);
            return new RegisterRes(true, "验证码发送成功!");
        } else {
            return new RegisterRes(false, "邮件发送失败!");
        }
    }

    @Override
    public RegisterRes verifyCheckCode(RegisterReq req) {
        // 验证两次密码是否一致
        if(!req.getRepwd().equals(req.getPwd())) return new RegisterRes(false, "两次密码不一致!");

        // 验证邮箱和昵称是否被注册过
        UserEntity userEntity1 = userService.selectOne(
                new Query().addCriteria(Criteria.where("email").is(req.getEmail()))
        );
        if(userEntity1 != null) {
            return new RegisterRes(false, "该邮箱已被注册!");
        }

        UserEntity userEntity2 = userService.selectOne(
                new Query().addCriteria(Criteria.where("nickname").is(req.getNickname()))
        );
        if(userEntity2 != null) {
            return new RegisterRes(false, "该昵称已被注册!");
        }

        // 验证验证码是否正确
        String checkCode = redisUtils.getCacheObject(CHECK_CODE_PREFIX+req.getEmail());
        if(checkCode == null || !checkCode.equals(req.getCheckCode())) {
            return new RegisterRes(false, "验证码错误!");
        } else {
            // 验证通过，删除验证码
            redisUtils.deleteObject(CHECK_CODE_PREFIX+req.getEmail());

            // 将用户入库,头像设置为默认头像
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            UserEntity userEntity = new UserEntity(req.getEmail(), passwordEncoder.encode(req.getPwd()), req.getNickname(),
                    bucket+":default/header-charile.jpg");
            userService.save(userEntity);
            return new RegisterRes(true, "注册成功!");
        }
    }

    /**
     * 生成随机码（length位）
     * @param length 随机码长度
     * @return 随机码
     */
    public static String generateRandomCode(int length) {
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        StringBuilder sb = new StringBuilder(length);
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            int index = random.nextInt(chars.length());
            sb.append(chars.charAt(index));
        }
        return sb.toString();
    }
}
